package com.gzhryc.servlet.jetty;

import com.gzhryc.common.logging.Logger;
import com.gzhryc.common.redis.RedisTools;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.server.session.AbstractSessionDataStore;
import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.Enumeration;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class JettyRedisSessionDataStore extends AbstractSessionDataStore {

	final static Logger log = Logger.getLogger(JettyRedisSessionDataStore.class);

	protected ConcurrentHashMap<String, SessionData> sessionIds;

	protected RedisTools redisTools;
	protected Integer redisDB;

	public JettyRedisSessionDataStore(RedisTools redisTools, Integer redisDB) {
		this.redisTools = redisTools;
		this.redisDB = redisDB;
		this.sessionIds = new ConcurrentHashMap<>();
	}

	@Override
	public boolean isPassivating() {
		return false;
	}

	@Override
	public boolean exists(String id) throws Exception {
		if (redisTools != null) {
			return redisTools.exists(redisDB, id);
		}
		return false;
	}

	@Override
	public boolean delete(String id) throws Exception {
		if (redisTools != null) {
			redisTools.delete(redisDB, id);
			sessionIds.remove(id);
			return true;
		}
		return false;
	}

	@Override
	public void doStore(String id, SessionData data, long lastSaveTime) throws Exception {
		ObjectOutputStream oos = null;
		try {
			if (data.getLastNode() == null) {
				data.setLastNode("");
			}
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(baos);
			oos.writeObject(data);
			String content = Base64.encodeBase64String(baos.toByteArray());
			if (redisTools.set(redisDB, id, content, 1800L)) {
				sessionIds.put(id, data);
			}
		} finally {
			if (oos != null) {
				oos.close();
			}
		}
	}

	@Override
	public SessionData doLoad(String id) throws Exception {
		ClassLoadingObjectInputStream ois = null;
		try {
			SessionData data = sessionIds.get(id);
			if (data != null) {
				return data;
			}
			String content = redisTools.get(redisDB, id);
			if (StringUtils.isNotBlank(content)) {
				ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decodeBase64(content));
				ois = new ClassLoadingObjectInputStream(bais);
				Object obj = ois.readObject();
				return SessionData.class.cast(obj);
			}
			return null;
		} finally {
			if (ois != null) {
				ois.close();
			}
		}
	}

	@Override
	public Set<String> doGetExpired(Set<String> candidates) {
		if (redisTools != null) {
			Enumeration<String> enumeration = sessionIds.keys();
			while (enumeration.hasMoreElements()) {
				String sessionId = enumeration.nextElement();
				if (!redisTools.exists(redisDB, sessionId)) {
					candidates.add(sessionId);
				}
			}
		}
		return candidates;
	}

}
